package uk.ac.jisc.depositmo.ui.cocoa;

/**
 * Copyright (c) 2011, University of Southampton
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * # Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 * # Redistributions in binary form must reproduce the above copyright notice, 
 *     this list of conditions and the following disclaimer in the documentation 
 *     and/or other materials provided with the distribution.
 * # Neither the name of the University of Southampton nor the names of its
 *     contributors may be used to endorse or promote products derived from this
 *     software without specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

/**
 * Provides utility methods for native Cocoa functionality (when available on the target platform.)
 * @author Mark Borkum <mark.borkum@gmail.com>
 *
 */
public class CocoaUIEnhancer extends AbstractCocoaUIEnhancer {
	protected static String getTitleFor(String appName, String string) {
		return string.replaceAll("\\{appName\\}", appName);
	}
	
	protected static String getTitleForAboutMenu(String appName) {
		return getTitleFor(appName, "About {appName}");
	}
	
	protected static String getTitleForHideApplicationMenu(String appName) {
		return getTitleFor(appName, "Hide {appName}");
	}
	
	protected static String getTitleForQuitMenu(String appName) {
		return getTitleFor(appName, "Quit {appName}");
	}
	
	private static final long
		kAboutMenuItem = 0,
		kPreferencesMenuItem = 2,
		kServicesMenuItem = 4,
		kHideApplicationMenuItem = 6,
//		kHideOtherApplicationsMenuItem = 7,
//		kShowAllApplicationsMenuItem = 8,
		kQuitMenuItem = 10;
	
	private Map<Long, Object> menuItems = new HashMap<Long, Object>();

	private Map<Long, Listener> actions = new HashMap<Long, Listener>();
	
	private String appName;
	
	public CocoaUIEnhancer(final Display display) {
		this(display, null);
	}
	
	public CocoaUIEnhancer(final Display display, String appName) {
		super(display);

		Object sharedApplication = invoke(classForName("org.eclipse.swt.internal.cocoa.NSApplication"), "sharedApplication");
		Object mainMenu = invoke(sharedApplication, "mainMenu");
		Object submenu = invoke(objc_NSMenu_itemAtIndex(mainMenu, 0), "submenu");
		
		Object aboutMenuitem = objc_NSMenu_itemAtIndex(submenu, kAboutMenuItem);
		this.menuItems.put(kAboutMenuItem, aboutMenuitem);
		
		objc_NSMenuItem_setAction(aboutMenuitem, sel_registerName(classForName("org.eclipse.swt.internal.cocoa.OS"), "aboutMenuItemSelected:"), new Listener() {
			public void handleEvent(Event e) {
				Listener listener = getActionAboutMenu();
				
				if (listener != null) {
					listener.handleEvent(e);
				}
			}
		});
		
		Object preferencesMenuItem = objc_NSMenu_itemAtIndex(submenu, kPreferencesMenuItem);
		this.menuItems.put(kPreferencesMenuItem, preferencesMenuItem);
		
		objc_NSMenuItem_setAction(preferencesMenuItem, sel_registerName(classForName("org.eclipse.swt.internal.cocoa.OS"), "preferencesMenuItemSelected:"), new Listener() {
			public void handleEvent(Event e) {
				Listener listener = getActionPreferencesMenu();
				
				if (listener != null) {
					listener.handleEvent(e);
				}
			}
		});
		
		Object servicesMenuItem = objc_NSMenu_itemAtIndex(submenu, kServicesMenuItem);
		this.menuItems.put(kServicesMenuItem, servicesMenuItem);
		
		this.setEnabledServicesMenu(false);
		
		Object hideApplicationMenuItem = objc_NSMenu_itemAtIndex(submenu, kHideApplicationMenuItem);
		this.menuItems.put(kHideApplicationMenuItem, hideApplicationMenuItem);
		
		objc_NSMenuItem_setAction(hideApplicationMenuItem, sel_registerName(classForName("org.eclipse.swt.internal.cocoa.OS"), "hideApplicationMenuItemSelected:"), new Listener() {
			public void handleEvent(Event e) {
				Listener listener = getActionHideApplicationMenu();
				
				if (listener != null) {
					listener.handleEvent(e);
				}
			}
		});
		
//		Object hideOtherApplicationsMenuItem = objc_NSMenu_itemAtIndex(submenu, kHideOtherApplicationsMenuItem);
//		this.menuItems.put(kHideOtherApplicationsMenuItem, hideOtherApplicationsMenuItem);
//		
//		Object showAllApplicationsMenuItem = objc_NSMenu_itemAtIndex(submenu, kShowAllApplicationsMenuItem);
//		this.menuItems.put(kShowAllApplicationsMenuItem, showAllApplicationsMenuItem);
		
		Object quitMenuItem = objc_NSMenu_itemAtIndex(submenu, kQuitMenuItem);
		this.menuItems.put(kQuitMenuItem, quitMenuItem);
		
		display.addListener(SWT.Close, new Listener() {
			public void handleEvent(Event e) {
				Listener listener = getActionQuitMenu();
				
				if (listener != null) {
					listener.handleEvent(e);
				}
			}
		});
		
		long sel_applicationShouldHandleReopen_ = sel_registerName(classForName("org.eclipse.swt.internal.cocoa.OS"), "applicationShouldHandleReopen:hasVisibleWindows:");
		
		objc_class_addMethod4c(sel_applicationShouldHandleReopen_);
		
		getHookObject().setListener(sel_applicationShouldHandleReopen_, new Listener() {
			public void handleEvent(Event e) {
				Event event = new Event();
				event.detail = 1;
				
				if (display != null) {
					invoke(Display.class, display, "sendEvent", new Class[] {
						int.class,
						Event.class
					}, new Object[] {
						SWT.Activate,
						event
					});
				}
			}
		});
		
		setAppName(appName);
	}
	
	public String getAppName() {
		return appName;
	}
	
	public void setAppName(String appName) {
		if (appName == null) {
			appName = Display.getAppName();
		}
		
		this.appName = appName;
		
		setTitleAboutMenu(getTitleForAboutMenu(appName));
		setTitleHideApplicationMenu(getTitleForHideApplicationMenu(appName));
		setTitleQuitMenu(getTitleForQuitMenu(appName));
	}
	
	public Listener getActionAboutMenu() {
		return this.actions.get(kAboutMenuItem);
	}

	public Listener getActionPreferencesMenu() {
		return this.actions.get(kPreferencesMenuItem);
	}

	public Listener getActionHideApplicationMenu() {
		return this.actions.get(kHideApplicationMenuItem);
	}
	
//	public Listener getActionHideOtherApplicationsMenu() {
//		return this.actions.get(kHideOtherApplicationsMenuItem);
//	}
//	
//	public Listener getActionShowAllApplicationsMenu() {
//		return this.actions.get(kShowAllApplicationsMenuItem);
//	}
	
	public Listener getActionQuitMenu() {
		return this.actions.get(kQuitMenuItem);
	}
	
	public void setActionAboutMenu(Listener listener) {
		this.actions.put(kAboutMenuItem, listener);
	}
	
	public void setActionPreferencesMenu(Listener listener) {
		this.actions.put(kPreferencesMenuItem, listener);
	}

	public void setActionHideApplicationMenu(Listener listener) {
		this.actions.put(kHideApplicationMenuItem, listener);
	}
	
//	public void setActionHideOtherApplicationsMenu(Listener listener) {
//		this.actions.put(kHideOtherApplicationsMenuItem, listener);
//	}
//
//	public void setActionShowAllApplicationsMenu(Listener listener) {
//		this.actions.put(kShowAllApplicationsMenuItem, listener);
//	}
	
	public void setActionQuitMenu(Listener listener) {
		this.actions.put(kQuitMenuItem, listener);
	}
	
	public void setEnabledAboutMenu(boolean enabled) {
		objc_NSMenuItem_setEnabled(this.menuItems.get(kAboutMenuItem), enabled);
	}
	
	public void setEnabledPreferencesMenu(boolean enabled) {
		objc_NSMenuItem_setEnabled(this.menuItems.get(kPreferencesMenuItem), enabled);
	}
	
	protected void setEnabledServicesMenu(boolean enabled) {
		objc_NSMenuItem_setEnabled(this.menuItems.get(kServicesMenuItem), enabled);
	}
	
	protected void setTitleAboutMenu(String title) {
		objc_NSMenuItem_setTitle(this.menuItems.get(kAboutMenuItem), title);
	}
	
	protected void setTitleHideApplicationMenu(String title) {
		objc_NSMenuItem_setTitle(this.menuItems.get(kHideApplicationMenuItem), title);
	}
	
	protected void setTitleQuitMenu(String title) {
		objc_NSMenuItem_setTitle(this.menuItems.get(kQuitMenuItem), title);
	}
}
